package com.cmcc.shared.network.interceptor

import android.text.TextUtils
import android.util.Log
import com.amap.api.col.n3.it
import com.cmcc.shared.SdkManager
import com.cmcc.shared.utils.L
import com.google.gson.JsonParser
import okhttp3.*
import okhttp3.internal.http.RequestLine.requestPath
import okio.Buffer
import java.io.IOException
import java.nio.charset.Charset
import java.util.concurrent.TimeUnit


class HttpLoggingInterceptor @JvmOverloads constructor(private val logger: Logger = Logger.DEFAULT) :
    Interceptor {

    @Volatile
    private var level = Level.NONE

    enum class Level {
        /**
         * No logs.
         */
        NONE,
        /**
         * Logs request and response lines.
         *
         *
         * Example:
         * <pre>`--> POST /greeting HTTP/1.1 (3-byte body)
         * <p/>
         * <-- HTTP/1.1 200 OK (22ms, 6-byte body)
        `</pre> *
         */
        BASIC,
        /**
         * Logs request and response lines and their respective headers.
         *
         *
         * Example:
         * <pre>`--> POST /greeting HTTP/1.1
         * Host: example.com
         * Content-Type: plain/text
         * Content-Length: 3
         * --> END POST
         * <p/>
         * <-- HTTP/1.1 200 OK (22ms)
         * Content-Type: plain/text
         * Content-Length: 6
         * <-- END HTTP
        `</pre> *
         */
        HEADERS,
        /**
         * Logs request and response lines and their respective headers and bodies (if present).
         *
         *
         * Example:
         * <pre>`--> POST /greeting HTTP/1.1
         * Host: example.com
         * Content-Type: plain/text
         * Content-Length: 3
         * <p/>
         * Hi?
         * --> END GET
         * <p/>
         * <-- HTTP/1.1 200 OK (22ms)
         * Content-Type: plain/text
         * Content-Length: 6
         * <p/>
         * Hello!
         * <-- END HTTP
        `</pre> *
         */
        BODY,
        URL
    }

    interface Logger {
        fun log(message: String)

        companion object {

            /**
             * A [Logger] defaults output appropriate for the current platform.
             */
            val DEFAULT: Logger = object : Logger {
                override fun log(message: String) {
                    //                Platform.get().logW(message);
                    L.d(HttpLoggingInterceptor::class.java.simpleName, message)

                    Log.e(HttpLoggingInterceptor::class.java.simpleName, message)
                }
            }
        }
    }

    /**
     * Change the level at which this interceptor logs.
     */
    fun setLevel(level: Level) {
        this.level = level
    }

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response? {


        val level = this.level

        val request = chain.request()
        if (level == Level.NONE) {
            return chain.proceed(request)
        }

        val logUrl = level == Level.URL
        val logBody = level == Level.BODY
        val logHeaders = logBody || level == Level.HEADERS

        val requestBody = request.body()
        val hasRequestBody = requestBody != null

        val connection = chain.connection()
        val protocol = if (connection != null) connection.protocol() else Protocol.HTTP_1_1
        var requestStartMessage =
            "--> " + request.method() + ' '.toString() + requestPath(request.url()) + ' '.toString() + protocol(
                protocol
            )
        if (!logHeaders && hasRequestBody) {
            requestStartMessage += " (" + requestBody!!.contentLength() + "-byte body)"
        }
        logger.log(requestStartMessage)

        if (logUrl) {
            var params = requestBody(request)
            params = params.replace("{", "")
            params = params.replace("}", "")
            params = params.replace("\"", "")
            params = params.replace(":", "=")
            params = params.replace(",", "&")
            logger.log("\nFeed Url: " + request.url().toString() + if (TextUtils.isEmpty(params.trim { it <= ' ' })) "" else "?$params")
        }

        //        List<String> params = new ArrayList<>();
        if (logHeaders) {
            val headers = request.headers()
            //            if (headers.size() > 0)
            //                requestUrl += "?";
            var i = 0
            val count = headers.size()
            while (i < count) {
                logger.log(headers.name(i) + ": " + headers.value(i))
                i++
                //                params.add(headers.name(i) + "=" + headers.value(i));
            }
            var params = requestBody(request)
            params = params.replace("{", "")
            params = params.replace("}", "")
            params = params.replace("\"", "")
            params = params.replace(":", "=")
            params = params.replace(",", "&")
            logger.log("\nFeed Url: " + request.url().toString() + if (TextUtils.isEmpty(params.trim { it <= ' ' })) "" else "?$params")

            var endMessage = "--> END " + request.method()
            if (logBody && hasRequestBody) {
                val buffer = Buffer()
                requestBody!!.writeTo(buffer)

                val charset = UTF8
                val contentType = requestBody.contentType()
                contentType?.charset(UTF8)

                logger.log("")
                logger.log(buffer.readString(charset))

                endMessage += " (" + requestBody.contentLength() + "-byte body)"
            }
            logger.log(endMessage)
        }

        /**
         * change by caixing for net timeout
         */
        var response: Response
        //创建 mediaType 和 content
        var mediaType: MediaType? = MediaType.parse("application/json;charset=UTF-8");
        val content = "\"{\"code\": 404, \"msg\": \"Net Error\", \"data\": \"null\"}\""
        try {
            response = chain.proceed(request)
            if (response.body() == null) {
                val builder = Response.Builder()
                    .headers(request.headers())
                    .code(100)
                    .message("Net Error")
                    .body(ResponseBody.create(mediaType, content))
                    .protocol(Protocol.HTTP_1_1)
                    .request(request)
                response = builder.build()
                SdkManager.netWorkListener?.netError()
                return  response;
            }
        } catch (e: Exception) {
            logger.log("e :" + e.message + "," + e.cause)

            val builder = Response.Builder()
                .headers(request.headers())
                .code(100)
                .message("Net Error")
                .body(ResponseBody.create(mediaType, content))
                .protocol(Protocol.HTTP_1_1)
                .request(request)
            response = builder.build()
            SdkManager.netWorkListener?.netError()
            return  response;

        }

        val startNs = System.nanoTime()
        val tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs)

        val responseBody = response.body()
        logger.log(
            "<-- " + protocol(response.protocol()) + ' '.toString() + response.code() + ' '.toString()
                    + response.message() + " (" + tookMs + "ms"
                    + (if (!logHeaders) ", " + responseBody!!.contentLength() + "-byte body" else "") + ')'.toString()
        )

        var buffer: Buffer? = null
        if (logHeaders) {
            val headers = response.headers()
            var i = 0
            val count = headers.size()
            while (i < count) {
                logger.log(headers.name(i) + ": " + headers.value(i))
                i++
            }

            var endMessage = "<-- END HTTP"
            if (logBody) {
                val source = responseBody!!.source()
                source.request(java.lang.Long.MAX_VALUE) // Buffer the entire body.
                buffer = source.buffer()

                var charset: Charset? = UTF8
                val contentType = responseBody.contentType()
                if (contentType != null) {
                    charset = contentType.charset(UTF8)
                }

                if (responseBody.contentLength() != 0L) {
                    logger.log("")
                    logger.log(buffer.clone().readString(charset!!))
                }

                endMessage += " (" + buffer.size() + "-byte body)"
            }
            logger.log(endMessage)
        }


        /**
         * add by caixing for 401 token unauthorized
         */
        if (response.isSuccessful && null != buffer) {
            val bufferString = buffer.clone().readUtf8()
            if (!bufferString.isNullOrEmpty()) {
                val res = JsonParser().parse(bufferString).asJsonObject

                val resCode =
                    try {
                        res.get("code").asInt
                    } catch (e: java.lang.Exception) {
                        200
                    }
                if (resCode == 401) {
                    SdkManager.netWorkListener?.unauthorized()
                }
            }
        }

        return response


    }

    companion object {
        private val UTF8 = Charset.forName("UTF-8")

        private fun protocol(protocol: Protocol): String {
            return if (protocol == Protocol.HTTP_1_0) "HTTP/1.0" else "HTTP/1.1"
        }

        private fun requestPath(url: HttpUrl): String {
            val path = url.encodedPath()
            val query = url.encodedQuery()
            return if (query != null) "$path?$query" else path
        }

        private fun requestBody(request: Request): String {
            try {
                val requestClone = request.newBuilder().build()
                if (requestClone.body() == null)
                    return ""
                else {
                    val buffer = Buffer()
                    requestClone.body()!!.writeTo(buffer)
                    return buffer.readUtf8()
                }
            } catch (e: IOException) {
                return "Exception: requestBodyToString()"
            }

        }
    }
}